//
//  WBNetworkManager.swift
//  Weibo
//
//  Created by cc on 9/15/17.
//  Copyright © 2017 cc. All rights reserved.
//

import UIKit
import AFNetworking

/*
    如果日常开发中， 发现网络请求返回的状态码是405，不支持的网络请求方法
 */
/// Swift 的枚举支持任意数据类型
enum WBHTTPMethod {
    case GET
    case POST
}




/// 网络管理工具
class WBNetworkManager: AFHTTPSessionManager {
    
    /// 静态区 / 常量 / 闭包
    // 在第一次访问时，执行闭包， 并且将结果保存在shared 常量中
    
    
//      static let shared = WBNetworkManager()
    @objc static let shared: WBNetworkManager = {
        //实例化对象
        let instance = WBNetworkManager()

        //设置响应反序列化支持的数据类型
        instance.responseSerializer.acceptableContentTypes?.insert("text/plain")

        //返回对象
        return instance
    }()
    
    
    
    /// 访问令牌，所有请求都基于此令牌(登录除外)
    /// 为了保护用户安全，访问令牌有时限，默认是三天
//    var accessToken: String?  //= "2.00NKbMECwXsXJB81a1831dffN9yRFC"
    /// 用户的微博id
//    var uid: String? = "1894373805"
    
    
    
    /// 用户帐户的懒加载属性
    @objc lazy var userAccount = WBUserAccount()
    
    
    
    /// 用户登录标记[计算型属性]
    @objc var userLogon: Bool {
        return  userAccount.access_token != nil
    }
    
    /// 专门负责拼接 token 的网络请求方法
    ///
    /// - Parameters:
    ///   - method: GET / POST
    ///   - URLString: URLString
    ///   - parameters: 参数字典
    ///   - name: 上传文件使用的字段名 ， 默认为nil ， 就不是上传文件
    ///   - data: 上传文件的二进制数据， 默认为nil， 不上传文件
    ///   - completion: 回调
    func tokenRequest(method: WBHTTPMethod = .GET ,URLString: String, parameters: [String: Any]?, name: String? = nil, data: Data? = nil, completion:@escaping (Any?, Bool)->()) {
        
        
        //处理token字典
        // 0 判断token 是否为nil， 为nil 直接返回 ,程序執行過程中，token一般不會爲nil
        guard let token  = userAccount.access_token else {
            // 发送通知，提示用户登录
            print("没有token， 需要登录")
            
            NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: nil)
            
            completion(nil, false)
            return
        }
        
        
        // 1> 判断 参数字典是否存在， 如果为nil ，新建一个字典
        var parameters = parameters
        
        if parameters == nil {
            //实例化字典
            parameters = [String: Any]()
        }
        
        // 2> 设置参数字典,  代码在此处一定有值
        parameters!["access_token"] = token
        
        // 3> 判断name 和 data
        if let name = name, let data = data {
            //上传文件
            upload(URLString: URLString, parameters: parameters, name: name, data: data, completion: completion)
        } else {
            //调用 request 发起真正的网络请求
            //request(URLString: URLString, parameters: parameters, completion: completion)
            request(method: method, URLString: URLString, parameters: parameters, completion: completion)
            
        }
        
        
    }
    
    
    
    // MARK: -封装 AFN 方法
    // 上传文件必须是POST 方法， GET只能获取数据
    /// 封装 AFN 的上传文件方法
    ///
    /// - Parameters:
    ///   - URLString: URLString
    ///   - parameters: 参数字典
    ///   - name: 接收上传数据的服务器字段
    ///   - data: 要上传的二进制数据
    ///   - completion: 回调
    func upload(URLString: String, parameters: [String: Any]?, name: String, data: Data, completion:@escaping (Any?, Bool)->()) {
        
        post(URLString, parameters: parameters, constructingBodyWith: { (formData) in
            
            //创建 formData
            /*
             1. data: 要上传的二进制数据
             2. name: 服务器接收到的字段名
             3. fileName: 保存在服务器的文件名
             4. mimeType: 告诉服务器上传文件的类型， 如果不想告诉，可以使用 application/octet-stream
             */
            formData.appendPart(withFileData: data, name: name, fileName: "XXX", mimeType: "application/octet-stream")
            
        }, progress: nil, success: { (_, json) in
            completion(json, true)
        }) { (task, error) in
            //针对 403 处理用户 token 过期
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                print("Token 过期了")
                
                //发送通知，提示用户登录(本方法不知道被谁调用，谁接收到通知，谁处理！)
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad token")
            }
            
            print("网络请求错误 \(error)")
            
            completion(nil, false)
        }
    }
    
    
    
    
    
    /// 封装 AFN 的GET / POST 请求
    ///
    /// - Parameters:
    ///   - method: GET / POST
    ///   - URLString: URLString
    ///   - parameters: 参数字典
    ///   - completion: 完成回调 [json( 字典 / 数组) ， 是否成功]
    func request(method: WBHTTPMethod = .GET ,URLString: String, parameters: [String: Any]?, completion:@escaping (Any?, Bool)->()) {
        
        //成功回调
        let success = { (task: URLSessionDataTask, json: Any?)->() in
            completion(json, true)
        }
        //失败回调
        let failure = { (task: URLSessionDataTask?, error: Error)->() in
            
            //针对 403 处理用户 token 过期
            if (task?.response as? HTTPURLResponse)?.statusCode == 403 {
                print("Token 过期了")
                
                //发送通知，提示用户登录(本方法不知道被谁调用，谁接收到通知，谁处理！)
                NotificationCenter.default.post(name: NSNotification.Name(rawValue: WBUserShouldLoginNotification), object: "bad token")
            }
            
            print("网络请求错误 \(error)")
            
            completion(nil, false)
        }
        
        
        if method == .GET {
            get(URLString, parameters: parameters, progress: nil, success: success, failure: failure)
        } else {
            post(URLString, parameters: parameters, progress: nil, success: success, failure: failure)
        }
        
    }
    
}

